package net.pushtime.aop.logging;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import net.pushtime.domain.Authority;
import net.pushtime.domain.SystemLog;
import net.pushtime.domain.SystemLogDic;
import net.pushtime.repository.SystemLogDicRepository;
import net.pushtime.repository.SystemLogRepository;
import net.pushtime.security.AuthoritiesConstants;
import net.pushtime.security.SecurityUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.core.env.Environment;
import org.springframework.data.domain.Example;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.time.Instant;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;

@Aspect
public class SystemLogAspect {
//    private final Logger log = LoggerFactory.getLogger(this.getClass());

    @Resource
    private HttpServletResponse response;

    @Resource
    private HttpServletRequest request;

    private final SystemLogDicRepository systemLogDicRepository;

    private final SystemLogRepository systemLogRepository;

    private final Environment env;


    public SystemLogAspect(Environment env, SystemLogDicRepository systemLogDicRepository, SystemLogRepository systemLogRepository) {
        this.systemLogDicRepository = systemLogDicRepository;
        this.systemLogRepository = systemLogRepository;
        this.env = env;
    }


    @Pointcut("within(net.pushtime.web.rest..*)")
    public void applicationPackagePointcut() {
        // Method is empty as this is just a Pointcut, the implementations are in the advices.
    }

    /**
     * Advice that logs when a method is entered and exited.
     *
     * @param joinPoint join point for advice
     * @return result
     * @throws Throwable throws IllegalArgumentException
     */
    @Around("applicationPackagePointcut()")
    public Object logAround(ProceedingJoinPoint joinPoint) throws Throwable {
        String uri = request.getRequestURI();
        String method = request.getMethod();
        SystemLogDic tmpDic = new SystemLogDic().url(uri).method(method);
        long count = systemLogDicRepository.count(Example.of(tmpDic));
        if (count <= 1) {
            Optional<SystemLogDic> systemLogDicOptional = systemLogDicRepository.findOne(Example.of(tmpDic));
            if (systemLogDicOptional.isPresent()) {
                SystemLogDic systemLogDic = systemLogDicOptional.get();
                String ip = request.getRemoteAddr();
                // 获取日志编码
                int code = systemLogDic.getCode();
                String user = SecurityUtils.getCurrentUserLogin().orElse(AuthoritiesConstants.ANONYMOUS);
                Instant now = Instant.now();
                // 记录系统日志信息
                SystemLog systemLog = new SystemLog();
                systemLog.setName(systemLogDic.getName());
                systemLog.setIp(ip);
                systemLog.setUrl(uri);
                systemLog.setMethod(method);
                systemLog.setCode(code);
                systemLog.setOperateBy(user);
                systemLog.setOperateDate(now);
                try {
                    Object result = joinPoint.proceed();
                    systemLog.setStatus(response.getStatus());
                    systemLog.result(1);
                    JSONArray args = JSONArray.parseArray(JSONArray.toJSONString(joinPoint.getArgs()));
                    Map<String, Object> map = new HashMap<>();
                    map.put("args", args);
                    map.put("result", result);
                    systemLog.setDetail(JSONObject.toJSONString(map));
                    systemLogRepository.save(systemLog);
                    // 不存在，跳过切面
                    return result;
                } catch (Exception e) {
                    systemLog.setStatus(response.getStatus());
                    systemLog.setResult(0);
                    JSONObject args = JSONObject.parseObject(JSONObject.toJSONString(request.getParameterMap()));
                    Map<String, Object> map = new HashMap<>();
                    map.put("args", args);
                    systemLog.setDetail(JSONObject.toJSONString(map));
                    systemLogRepository.save(systemLog);
                    throw e;
                }
            }
        }
        return joinPoint.proceed();
    }
}
